package com.etrans.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.etrans.util.thread.WaitLock;
import com.etrans.v2.common.utils.DateUtils;
import com.etrans.v2.modules.log.entity.LogDomain;
import com.etrans.v2.modules.log.service.LogService;
import com.etrans.v2.modules.webserviceXml.entity.WebserviceXml;
import com.etrans.v2.modules.webserviceXml.service.WebserviceXmlService;

/**
 * 插入压测日志
 *
 */
public class LogIbatisUtils {
	
	
	public LogService getLogService(){
		return (LogService)SpringWebContextUtil.getApplicationContext().getBean("LogService");
	}
	
	public WebserviceXmlService getWebserviceXmlService(){
		return (WebserviceXmlService)SpringWebContextUtil.getApplicationContext().getBean("WebserviceXmlService");
	}
	
	private void saveXmlInstock(WebserviceXml obj) {
		try{
			getWebserviceXmlService().save(obj);
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}
	
	private void saveLog(LogDomain logDomain) {
		try {
			getLogService().saveAll(logDomain);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void saveLog(String interfaceName,Date start,String status){
		/**
		if("true".equals(ConfigUtil.getIsopenlog())){
			Date end = DateUtils.getCurrentDate();
			LogDomain log = new LogDomain(interfaceName,DateUtils.formatDateMilliTime(start),DateUtils.formatDateMilliTime(end),end.getTime() - start.getTime(),status);
			//saveLog(log);
			pushLogObj(log);
		}
		**/
	}
	
	public void saveXMLLog(String postResponse,String postInterface,String methodName,int status,String xmlContent,String memberId){
		//WebserviceXml xmlLog = new WebserviceXml(postResponse,postInterface,methodName,status,xmlContent,memberId);
		//pushLogObj(xmlLog);
		//getWebserviceXmlService().save(xmlLog);
	}
	
	public LogIbatisUtils(){
		queue = new ConcurrentLinkedQueue<Object>();
		workerList = new ArrayList<LogUtilRunnable>();
		lockList = new ArrayList<WaitLock>();
		futureList = new ArrayList<Future<?>>();
		this.status = STATUS_STOPPED;
	}
	
	private static LogIbatisUtils instance = null;
	private final static Lock lock = new ReentrantLock();
	private Queue<Object> queue;
	private int workerIndex;
	private int workers;
	private List<WaitLock> lockList;
	private List<LogUtilRunnable> workerList;
	private final static byte STATUS_STARTING = 0;
	private final static byte STATUS_STARTED = 1;
	private final static byte STATUS_STOPPING = 2;
	private final static byte STATUS_STOPPED = 3;
	private volatile byte status;
	private ExecutorService executorService;
	private List<Future<?>> futureList;
	
	public static LogIbatisUtils getInstance() {
		lock.lock();
		try {
			if (instance == null) {
				instance = new LogIbatisUtils();
			}
			return instance;
		} finally {
			lock.unlock();
		}
	}
	public boolean pushLogObj(Object log) {
		boolean result = false;
		result = queue.offer(log);
		System.out.println("=======================================: " + queue.size());
		lock.lock();
		try {
			for (int i = 0; i < workers; i++) {
				WaitLock waitLock = lockList.get(workerIndex);
				LogUtilRunnable runnable = workerList.get(workerIndex);
				workerIndex = (workerIndex + 1) % workers;
				if (runnable.getStatus() == LogUtilRunnable.STATUS_RUNNING) {
					waitLock.wakeAll();
					break;
				}
			}
		} finally {
			lock.unlock();
		}
		return result;
	}
	
	private Object pollLog() {
		return queue.poll();
	}
	
	private class LogUtilRunnable implements Runnable {

		private final static byte STATUS_RUNNING = 0;
		private final static byte STATUS_STOPPING = 1;
		private final static byte STATUS_STOPPED = 2;
		private volatile byte status;
		private WaitLock lock;

		public LogUtilRunnable(WaitLock lock) {
			this.lock = lock;
			this.status = STATUS_RUNNING;
		}
		public byte getStatus() {
			return status;
		}
		public void destory() {
			this.status = STATUS_STOPPING;
			this.lock.wakeAll();
		}
		@Override
		public void run() {
			Object obj = null;
			// 从队列中取出数据
			obj = LogIbatisUtils.this.pollLog();
			while (status == STATUS_RUNNING || obj != null) {
				try {
					if (obj == null) {
						// 等待5s或被唤醒
						lock.waitFor(5000);
					} else {
						if(obj instanceof LogDomain){
							saveLog((LogDomain)obj);
						}else if(obj instanceof WebserviceXml){
							saveXmlInstock((WebserviceXml)obj);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				// 从队列中取出数据
				obj = LogIbatisUtils.this.pollLog();
			}
			this.status = STATUS_STOPPED;
		}
	}
	
	public void start(int workers) {
		lock.lock();
		try {
			if (this.status != STATUS_STOPPED) {
				return;
			}
			this.status = STATUS_STARTING;
			this.workers = workers;
			this.workerIndex = 0;
			executorService = Executors.newFixedThreadPool(workers, new ThreadFactory() {
				private final AtomicInteger index = new AtomicInteger(0);

				@Override
				public Thread newThread(Runnable r) {
					return new Thread(r, "LogIbatisUtils_" + index.getAndIncrement());
				}

			});
			for (int i = 0; i < workers; i++) {
				WaitLock waitLock = new WaitLock();
				lockList.add(waitLock);
				LogUtilRunnable runnable = new LogUtilRunnable(waitLock);
				workerList.add(runnable);
				Future<?> future = executorService.submit(runnable);
				futureList.add(future);
			}
			this.status = STATUS_STARTED;
		} finally {
			lock.unlock();
		}
	}
	

}
